home *** CD-ROM | disk | FTP | other *** search
/ Turnbull China Bikeride / Turnbull China Bikeride - Disc 2.iso / STUTTGART / LANG / ADA / GNAT / !gcc / adainc / 2 / adb / a-textio < prev    next >
Text File  |  1996-02-12  |  43KB  |  1,650 lines

  1. ------------------------------------------------------------------------------
  2. --                                                                          --
  3. --                         GNAT RUNTIME COMPONENTS                          --
  4. --                                                                          --
  5. --                          A D A . T E X T _ I O                           --
  6. --                                                                          --
  7. --                                 B o d y                                  --
  8. --                                                                          --
  9. --                            $Revision: 1.57 $                             --
  10. --                                                                          --
  11. --   Copyright (C) 1992,1993,1994,1995,1996 Free Software Foundation, Inc.  --
  12. --                                                                          --
  13. -- GNAT is free software;  you can  redistribute it  and/or modify it under --
  14. -- terms of the  GNU General Public License as published  by the Free Soft- --
  15. -- ware  Foundation;  either version 2,  or (at your option) any later ver- --
  16. -- sion.  GNAT is distributed in the hope that it will be useful, but WITH- --
  17. -- OUT ANY WARRANTY;  without even the  implied warranty of MERCHANTABILITY --
  18. -- or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License --
  19. -- for  more details.  You should have  received  a copy of the GNU General --
  20. -- Public License  distributed with GNAT;  see file COPYING.  If not, write --
  21. -- to  the Free Software Foundation,  59 Temple Place - Suite 330,  Boston, --
  22. -- MA 02111-1307, USA.                                                      --
  23. --                                                                          --
  24. -- As a special exception,  if other files  instantiate  generics from this --
  25. -- unit, or you link  this unit with other files  to produce an executable, --
  26. -- this  unit  does not  by itself cause  the resulting  executable  to  be --
  27. -- covered  by the  GNU  General  Public  License.  This exception does not --
  28. -- however invalidate  any other reasons why  the executable file  might be --
  29. -- covered by the  GNU Public License.                                      --
  30. --                                                                          --
  31. -- GNAT was originally developed  by the GNAT team at  New York University. --
  32. -- It is now maintained by Ada Core Technologies Inc (http://www.gnat.com). --
  33. --                                                                          --
  34. ------------------------------------------------------------------------------
  35.  
  36. with Ada.Streams;          use Ada.Streams;
  37. with Interfaces.C_Streams; use Interfaces.C_Streams;
  38. with System;
  39. with System.File_IO;
  40. with Unchecked_Conversion;
  41. with Unchecked_Deallocation;
  42.  
  43. pragma Elaborate_All (System.File_IO);
  44. --  Needed because of calls to Chain_File in package body elaboration
  45.  
  46. package body Ada.Text_IO is
  47.  
  48.    package FIO renames System.File_IO;
  49.  
  50.    subtype AP is FCB.AFCB_Ptr;
  51.  
  52.    function To_FCB is new Unchecked_Conversion (File_Mode, FCB.File_Mode);
  53.    function To_TIO is new Unchecked_Conversion (FCB.File_Mode, File_Mode);
  54.    use type FCB.File_Mode;
  55.  
  56.    -------------------
  57.    -- AFCB_Allocate --
  58.    -------------------
  59.  
  60.    function AFCB_Allocate (Control_Block : Text_AFCB) return FCB.AFCB_Ptr is
  61.    begin
  62.       return new Text_AFCB;
  63.    end AFCB_Allocate;
  64.  
  65.    ----------------
  66.    -- AFCB_Close --
  67.    ----------------
  68.  
  69.    procedure AFCB_Close (File : access Text_AFCB) is
  70.    begin
  71.       --  If the file being closed is one of the current files, then close
  72.       --  the corresponding current file. It is not clear that this action
  73.       --  is required (RM A.10.3(23)) but it seems reasonable, and besides
  74.       --  ACVC test CE3208A expects this behavior.
  75.  
  76.       if File = Current_In then
  77.          Current_In := null;
  78.       elsif File = Current_Out then
  79.          Current_Out := null;
  80.       elsif File = Current_Err then
  81.          Current_Err := null;
  82.       end if;
  83.  
  84.       Terminate_Line (File);
  85.    end AFCB_Close;
  86.  
  87.    ---------------
  88.    -- AFCB_Free --
  89.    ---------------
  90.  
  91.    procedure AFCB_Free (File : access Text_AFCB) is
  92.       type FCB_Ptr is access all Text_AFCB;
  93.       FT : FCB_Ptr := File;
  94.  
  95.       procedure Free is new Unchecked_Deallocation (Text_AFCB, FCB_Ptr);
  96.  
  97.    begin
  98.       Free (FT);
  99.    end AFCB_Free;
  100.  
  101.    -----------
  102.    -- Close --
  103.    -----------
  104.  
  105.    procedure Close (File : in out File_Type) is
  106.    begin
  107.       FIO.Close (AP (File));
  108.    end Close;
  109.  
  110.    ---------
  111.    -- Col --
  112.    ---------
  113.  
  114.    --  Note: we assume that it is impossible in practice for the column
  115.    --  to exceed the value of Count'Last, i.e. no check is required for
  116.    --  overflow raising layout error.
  117.  
  118.    function Col (File : in File_Type) return Positive_Count is
  119.    begin
  120.       FIO.Check_File_Open (AP (File));
  121.       return File.Col;
  122.    end Col;
  123.  
  124.    function Col return Positive_Count is
  125.    begin
  126.       return Col (Current_Out);
  127.    end Col;
  128.  
  129.    ------------
  130.    -- Create --
  131.    ------------
  132.  
  133.    procedure Create
  134.      (File : in out File_Type;
  135.       Mode : in File_Mode := Out_File;
  136.       Name : in String := "";
  137.       Form : in String := "")
  138.    is
  139.       File_Control_Block : Text_AFCB;
  140.  
  141.    begin
  142.       FIO.Open (File_Ptr  => AP (File),
  143.                 Dummy_FCB => File_Control_Block,
  144.                 Mode      => To_FCB (Mode),
  145.                 Name      => Name,
  146.                 Form      => Form,
  147.                 Amethod   => 'T',
  148.                 Creat     => True,
  149.                 Text      => True);
  150.    end Create;
  151.  
  152.    -------------------
  153.    -- Current_Error --
  154.    -------------------
  155.  
  156.    function Current_Error return File_Type is
  157.    begin
  158.       return Current_Err;
  159.    end Current_Error;
  160.  
  161.    function Current_Error return File_Access is
  162.    begin
  163.       return Current_Err'Access;
  164.    end Current_Error;
  165.  
  166.    -------------------
  167.    -- Current_Input --
  168.    -------------------
  169.  
  170.    function Current_Input return File_Type is
  171.    begin
  172.       return Current_In;
  173.    end Current_Input;
  174.  
  175.    function Current_Input return File_Access is
  176.    begin
  177.       return Current_In'Access;
  178.    end Current_Input;
  179.  
  180.    --------------------
  181.    -- Current_Output --
  182.    --------------------
  183.  
  184.    function Current_Output return File_Type is
  185.    begin
  186.       return Current_Out;
  187.    end Current_Output;
  188.  
  189.    function Current_Output return File_Access is
  190.    begin
  191.       return Current_Out'Access;
  192.    end Current_Output;
  193.  
  194.    ------------
  195.    -- Delete --
  196.    ------------
  197.  
  198.    procedure Delete (File : in out File_Type) is
  199.    begin
  200.       FIO.Delete (AP (File));
  201.    end Delete;
  202.  
  203.    -----------------
  204.    -- End_Of_File --
  205.    -----------------
  206.  
  207.    function End_Of_File (File : in File_Type) return Boolean is
  208.       ch  : int;
  209.  
  210.    begin
  211.       FIO.Check_Read_Status (AP (File));
  212.  
  213.       if File.Before_LM then
  214.  
  215.          if File.Before_LM_PM then
  216.             return Nextc (File) = EOF;
  217.          end if;
  218.  
  219.       else
  220.          ch := Getc (File);
  221.  
  222.          if ch = EOF then
  223.             return True;
  224.  
  225.          elsif ch /= LM then
  226.             Ungetc (ch, File);
  227.             return False;
  228.  
  229.          else -- ch = LM
  230.             File.Before_LM := True;
  231.          end if;
  232.       end if;
  233.  
  234.       --  Here we are just past the line mark with Before_LM set so that we
  235.       --  do not have to try to back up past the LM, thus avoiding the need
  236.       --  to back up more than one character.
  237.  
  238.       ch := Getc (File);
  239.  
  240.       if ch = EOF then
  241.          return True;
  242.  
  243.       elsif ch = PM and then File.Is_Regular_File then
  244.          File.Before_LM_PM := True;
  245.          return Nextc (File) = EOF;
  246.  
  247.       --  Here if neither EOF nor PM followed end of line
  248.  
  249.       else
  250.          Ungetc (ch, File);
  251.          return False;
  252.       end if;
  253.  
  254.    end End_Of_File;
  255.  
  256.    function End_Of_File return Boolean is
  257.    begin
  258.       return End_Of_File (Current_In);
  259.    end End_Of_File;
  260.  
  261.    -----------------
  262.    -- End_Of_Line --
  263.    -----------------
  264.  
  265.    function End_Of_Line (File : in File_Type) return Boolean is
  266.       ch : int;
  267.  
  268.    begin
  269.       FIO.Check_Read_Status (AP (File));
  270.  
  271.       if File.Before_LM then
  272.          return True;
  273.  
  274.       else
  275.          ch := Getc (File);
  276.  
  277.          if ch = EOF then
  278.             return True;
  279.  
  280.          else
  281.             Ungetc (ch, File);
  282.             return (ch = LM);
  283.          end if;
  284.       end if;
  285.    end End_Of_Line;
  286.  
  287.    function End_Of_Line return Boolean is
  288.    begin
  289.       return End_Of_Line (Current_In);
  290.    end End_Of_Line;
  291.  
  292.    -----------------
  293.    -- End_Of_Page --
  294.    -----------------
  295.  
  296.    function End_Of_Page (File : in File_Type) return Boolean is
  297.       ch  : int;
  298.  
  299.    begin
  300.       FIO.Check_Read_Status (AP (File));
  301.  
  302.       if not File.Is_Regular_File then
  303.          return False;
  304.  
  305.       elsif File.Before_LM then
  306.          if File.Before_LM_PM then
  307.             return True;
  308.          end if;
  309.  
  310.       else
  311.          ch := Getc (File);
  312.  
  313.          if ch = EOF then
  314.             return True;
  315.  
  316.          elsif ch /= LM then
  317.             Ungetc (ch, File);
  318.             return False;
  319.  
  320.          else -- ch = LM
  321.             File.Before_LM := True;
  322.          end if;
  323.       end if;
  324.  
  325.       --  Here we are just past the line mark with Before_LM set so that we
  326.       --  do not have to try to back up past the LM, thus avoiding the need
  327.       --  to back up more than one character.
  328.  
  329.       ch := Nextc (File);
  330.  
  331.       return ch = PM or else ch = EOF;
  332.    end End_Of_Page;
  333.  
  334.    function End_Of_Page return Boolean is
  335.    begin
  336.       return End_Of_Page (Current_In);
  337.    end End_Of_Page;
  338.  
  339.    -----------
  340.    -- Flush --
  341.    -----------
  342.  
  343.    procedure Flush (File : in File_Type) is
  344.    begin
  345.       FIO.Flush (AP (File));
  346.    end Flush;
  347.  
  348.    procedure Flush is
  349.    begin
  350.       Flush (Current_Out);
  351.    end Flush;
  352.  
  353.    ----------
  354.    -- Form --
  355.    ----------
  356.  
  357.    function Form (File : in File_Type) return String is
  358.    begin
  359.       return FIO.Form (AP (File));
  360.    end Form;
  361.  
  362.    ---------
  363.    -- Get --
  364.    ---------
  365.  
  366.    procedure Get
  367.      (File : in File_Type;
  368.       Item : out Character)
  369.    is
  370.       ch : int;
  371.  
  372.    begin
  373.       FIO.Check_Read_Status (AP (File));
  374.  
  375.       if File.Before_LM then
  376.          File.Before_LM := False;
  377.          File.Before_LM_PM := False;
  378.          File.Col := 1;
  379.  
  380.          if File.Before_LM_PM then
  381.             File.Line := 1;
  382.             File.Page := File.Page + 1;
  383.             File.Before_LM_PM := False;
  384.  
  385.          else
  386.             File.Line := File.Line + 1;
  387.          end if;
  388.       end if;
  389.  
  390.       loop
  391.          ch := Getc (File);
  392.  
  393.          if ch = EOF then
  394.             raise End_Error;
  395.  
  396.          elsif ch = LM then
  397.             File.Line := File.Line + 1;
  398.             File.Col := 1;
  399.  
  400.          elsif ch = PM and then File.Is_Regular_File then
  401.             File.Page := File.Page + 1;
  402.             File.Line := 1;
  403.  
  404.          else
  405.             Item := Character'Val (ch);
  406.             File.Col := File.Col + 1;
  407.             return;
  408.          end if;
  409.       end loop;
  410.    end Get;
  411.  
  412.    procedure Get (Item : out Character) is
  413.    begin
  414.       Get (Current_In, Item);
  415.    end Get;
  416.  
  417.    procedure Get
  418.      (File : in File_Type;
  419.       Item : out String)
  420.    is
  421.       ch : int;
  422.       J  : Natural;
  423.  
  424.    begin
  425.       FIO.Check_Read_Status (AP (File));
  426.  
  427.       if File.Before_LM then
  428.          File.Before_LM := False;
  429.          File.Before_LM_PM := False;
  430.          File.Col := 1;
  431.  
  432.          if File.Before_LM_PM then
  433.             File.Line := 1;
  434.             File.Page := File.Page + 1;
  435.             File.Before_LM_PM := False;
  436.  
  437.          else
  438.             File.Line := File.Line + 1;
  439.          end if;
  440.       end if;
  441.  
  442.       J := Item'First;
  443.       while J <= Item'Last loop
  444.          ch := Getc (File);
  445.  
  446.          if ch = EOF then
  447.             raise End_Error;
  448.  
  449.          elsif ch = LM then
  450.             File.Line := File.Line + 1;
  451.             File.Col := 1;
  452.  
  453.          elsif ch = PM and then File.Is_Regular_File then
  454.             File.Page := File.Page + 1;
  455.             File.Line := 1;
  456.  
  457.          else
  458.             Item (J) := Character'Val (ch);
  459.             J := J + 1;
  460.             File.Col := File.Col + 1;
  461.          end if;
  462.       end loop;
  463.    end Get;
  464.  
  465.    procedure Get (Item : out String) is
  466.    begin
  467.       Get (Current_In, Item);
  468.    end Get;
  469.  
  470.    ----------
  471.    -- Getc --
  472.    ----------
  473.    function Getc (File : File_Type) return int is
  474.       ch : int;
  475.  
  476.    begin
  477.       ch := fgetc (File.Stream);
  478.  
  479.       if ch = EOF and then ferror (File.Stream) /= 0 then
  480.          raise Device_Error;
  481.       else
  482.          return ch;
  483.       end if;
  484.    end Getc;
  485.  
  486.    -------------------
  487.    -- Get_Immediate --
  488.    -------------------
  489.  
  490.    --  More work required here ???
  491.  
  492.    procedure Get_Immediate
  493.      (File : in File_Type;
  494.       Item : out Character)
  495.    is
  496.       ch          : int;
  497.       end_of_file : int;
  498.  
  499.       procedure getc_immediate
  500.         (stream : FILEs; ch : out int; end_of_file : out int);
  501.       pragma Import (C, getc_immediate);
  502.  
  503.    begin
  504.       FIO.Check_Read_Status (AP (File));
  505.  
  506.       if File.Before_LM then
  507.          File.Before_LM := False;
  508.          File.Before_LM_PM := False;
  509.          ch := LM;
  510.  
  511.       else
  512.          getc_immediate (File.Stream, ch, end_of_file);
  513.  
  514.          if ferror (File.Stream) /= 0 then
  515.             raise Device_Error;
  516.          elsif end_of_file /= 0 then
  517.             raise End_Error;
  518.          end if;
  519.       end if;
  520.  
  521.       Item := Character'Val (ch);
  522.  
  523.    end Get_Immediate;
  524.  
  525.    procedure Get_Immediate
  526.      (Item : out Character)
  527.    is
  528.    begin
  529.       Get_Immediate (Current_In, Item);
  530.    end Get_Immediate;
  531.  
  532.    procedure Get_Immediate
  533.      (File      : in File_Type;
  534.       Item      : out Character;
  535.       Available : out Boolean)
  536.    is
  537.       ch          : int;
  538.       end_of_file : int;
  539.       avail       : int;
  540.  
  541.       procedure getc_immediate_nowait
  542.         (stream      : FILEs;
  543.          ch          : out int;
  544.          end_of_file : out int;
  545.          avail       : out int);
  546.       pragma Import (C, getc_immediate_nowait);
  547.  
  548.    begin
  549.       FIO.Check_Read_Status (AP (File));
  550.  
  551.       if File.Before_LM then
  552.          File.Before_LM := False;
  553.          File.Before_LM_PM := False;
  554.          ch := LM;
  555.  
  556.       else
  557.          getc_immediate_nowait (File.Stream, ch, end_of_file, avail);
  558.  
  559.          if ferror (File.Stream) /= 0 then
  560.             raise Device_Error;
  561.  
  562.          elsif end_of_file /= 0 then
  563.             raise End_Error;
  564.  
  565.          elsif avail = 0 then
  566.             Available := False;
  567.  
  568.          else
  569.             Available := True;
  570.             Item := Character'Val (ch);
  571.          end if;
  572.       end if;
  573.  
  574.    end Get_Immediate;
  575.  
  576.    procedure Get_Immediate
  577.      (Item      : out Character;
  578.       Available : out Boolean)
  579.    is
  580.    begin
  581.       Get_Immediate (Current_In, Item, Available);
  582.    end Get_Immediate;
  583.  
  584.    --------------
  585.    -- Get_Line --
  586.    --------------
  587.  
  588.    procedure Get_Line
  589.      (File : in File_Type;
  590.       Item : out String;
  591.       Last : out Natural)
  592.    is
  593.       ch : int;
  594.  
  595.    begin
  596.       FIO.Check_Read_Status (AP (File));
  597.       Last := Item'First - 1;
  598.  
  599.       --  Immediate exit for null string, this is a case in which we do not
  600.       --  need to test for end of file and we do not skip a line mark under
  601.       --  any circumstances.
  602.  
  603.       if Last >= Item'Last then
  604.          return;
  605.       end if;
  606.  
  607.       --  Here we have at least one character, if we are immediately before
  608.       --  a line mark, then we will just skip past it storing no characters.
  609.  
  610.       if File.Before_LM then
  611.          File.Before_LM := False;
  612.          File.Before_LM_PM := False;
  613.  
  614.       --  Otherwise we need to read some characters
  615.  
  616.       else
  617.          ch := Getc (File);
  618.  
  619.          --  If we are at the end of file now, it means we are trying to
  620.          --  skip a file terminator and we raise End_Error (RM A.10.7(20))
  621.  
  622.          if ch = EOF then
  623.             raise End_Error;
  624.          end if;
  625.  
  626.          --  Loop through characters. Don't bother if we hit a page mark,
  627.          --  since in normal files, page marks can only follow line marks
  628.          --  in any case and we only promise to treat the page nonsense
  629.          --  correctly in the absense of such rogue page marks.
  630.  
  631.          loop
  632.             --  Exit the loop if read is terminated by encountering line mark
  633.  
  634.             exit when ch = LM;
  635.  
  636.             --  Otherwise store the character, note that we know that ch is
  637.             --  something other than LM or EOF. It could possibly be a page
  638.             --  mark if there is a stray page mark in the middle of a line,
  639.             --  but this is not an official page mark in any case, since
  640.             --  official page marks can only follow a line mark. The whole
  641.             --  page business is pretty much nonsense anyway, so we do not
  642.             --  want to waste time trying to make sense out of non-standard
  643.             --  page marks in the file! This means that the behavior of
  644.             --  Get_Line is different from repeated Get of a character, but
  645.             --  that's too bad. We only promise that page numbers etc make
  646.             --  sense if the file is formatted in a standard manner.
  647.  
  648.             --  Note: we do not adjust the column number because it is quicker
  649.             --  to adjust it once at the end of the operation than incrementing
  650.             --  it each time around the loop.
  651.  
  652.             Last := Last + 1;
  653.             Item (Last) := Character'Val (ch);
  654.  
  655.             --  All done if the string is full, this is the case in which
  656.             --  we do not skip the following line mark. We need to adjust
  657.             --  the column number in this case.
  658.  
  659.             if Last = Item'Last then
  660.                File.Col := File.Col + Count (Item'Length);
  661.                return;
  662.             end if;
  663.  
  664.             --  Otherwise read next character. We also exit from the loop if
  665.             --  we read an end of file. This is the case where the last line
  666.             --  is not terminated with a line mark, and we consider that there
  667.             --  is an implied line mark in this case (this is a non-standard
  668.             --  file, but it is nice to treat it reasonably).
  669.  
  670.             ch := Getc (File);
  671.             exit when ch = EOF;
  672.          end loop;
  673.       end if;
  674.  
  675.       --  We have skipped past, but not stored, a line mark. Skip following
  676.       --  page mark if one follows, but do not do this for a non-regular
  677.       --  file (since otherwise we get annoying wait for an extra character)
  678.  
  679.       File.Line := File.Line + 1;
  680.       File.Col := 1;
  681.  
  682.       if File.Before_LM_PM then
  683.          File.Line := 1;
  684.          File.Before_LM_PM := False;
  685.          File.Page := File.Page + 1;
  686.  
  687.       elsif File.Is_Regular_File then
  688.          ch := Getc (File);
  689.  
  690.          if ch = PM and then File.Is_Regular_File then
  691.             File.Line := 1;
  692.             File.Page := File.Page + 1;
  693.          else
  694.             Ungetc (ch, File);
  695.          end if;
  696.       end if;
  697.    end Get_Line;
  698.  
  699.    procedure Get_Line
  700.      (Item : out String;
  701.       Last : out Natural)
  702.    is
  703.    begin
  704.       Get_Line (Current_In, Item, Last);
  705.    end Get_Line;
  706.  
  707.    -------------
  708.    -- Is_Open --
  709.    -------------
  710.  
  711.    function Is_Open (File : in File_Type) return Boolean is
  712.    begin
  713.       return FIO.Is_Open (AP (File));
  714.    end Is_Open;
  715.  
  716.    ----------
  717.    -- Line --
  718.    ----------
  719.  
  720.    --  Note: we assume that it is impossible in practice for the line
  721.    --  to exceed the value of Count'Last, i.e. no check is required for
  722.    --  overflow raising layout error.
  723.  
  724.    function Line (File : in File_Type) return Positive_Count is
  725.    begin
  726.       FIO.Check_File_Open (AP (File));
  727.       return File.Line;
  728.    end Line;
  729.  
  730.    function Line return Positive_Count is
  731.    begin
  732.       return Line (Current_Out);
  733.    end Line;
  734.  
  735.    -----------------
  736.    -- Line_Length --
  737.    -----------------
  738.  
  739.    function Line_Length (File : in File_Type) return Count is
  740.    begin
  741.       FIO.Check_Write_Status (AP (File));
  742.       return File.Line_Length;
  743.    end Line_Length;
  744.  
  745.    function Line_Length return Count is
  746.    begin
  747.       return Line_Length (Current_Out);
  748.    end Line_Length;
  749.  
  750.    ----------------
  751.    -- Look_Ahead --
  752.    ----------------
  753.  
  754.    procedure Look_Ahead
  755.      (File        : in File_Type;
  756.       Item        : out Character;
  757.       End_Of_Line : out Boolean)
  758.    is
  759.       ch : int;
  760.  
  761.    begin
  762.       FIO.Check_Read_Status (AP (File));
  763.  
  764.       if File.Before_LM then
  765.          End_Of_Line := True;
  766.          Item := Ascii.NUL;
  767.  
  768.       else
  769.          ch := Nextc (File);
  770.  
  771.          if ch = LM
  772.            or else ch = EOF
  773.            or else (ch = PM and then File.Is_Regular_File)
  774.          then
  775.             End_Of_Line := True;
  776.             Item := Ascii.NUL;
  777.          else
  778.             End_Of_Line := False;
  779.             Item := Character'Val (ch);
  780.          end if;
  781.       end if;
  782.    end Look_Ahead;
  783.  
  784.    procedure Look_Ahead
  785.      (Item        : out Character;
  786.       End_Of_Line : out Boolean)
  787.    is
  788.    begin
  789.       Look_Ahead (Standard_In, Item, End_Of_Line);
  790.    end Look_Ahead;
  791.  
  792.    ----------
  793.    -- Mode --
  794.    ----------
  795.  
  796.    function Mode (File : in File_Type) return File_Mode is
  797.    begin
  798.       return To_TIO (FIO.Mode (AP (File)));
  799.    end Mode;
  800.  
  801.    ----------
  802.    -- Name --
  803.    ----------
  804.  
  805.    function Name (File : in File_Type) return String is
  806.    begin
  807.       return FIO.Name (AP (File));
  808.    end Name;
  809.  
  810.    --------------
  811.    -- New_Line --
  812.    --------------
  813.  
  814.    procedure New_Line
  815.      (File    : in File_Type;
  816.       Spacing : in Positive_Count := 1)
  817.    is
  818.    begin
  819.       --  Raise Constraint_Error if out of range value. The reason for this
  820.       --  explicit test is that we don't want junk values around, even if
  821.       --  checks are off in the caller.
  822.  
  823.       if Spacing not in Positive_Count then
  824.          raise Constraint_Error;
  825.       end if;
  826.  
  827.       FIO.Check_Write_Status (AP (File));
  828.  
  829.       for K in 1 .. Spacing loop
  830.          Putc (LM, File);
  831.          File.Line := File.Line + 1;
  832.  
  833.          if File.Page_Length /= 0
  834.            and then File.Line > File.Page_Length
  835.          then
  836.             Putc (PM, File);
  837.             File.Line := 1;
  838.             File.Page := File.Page + 1;
  839.          end if;
  840.       end loop;
  841.  
  842.       File.Col := 1;
  843.    end New_Line;
  844.  
  845.    procedure New_Line (Spacing : in Positive_Count := 1) is
  846.    begin
  847.       New_Line (Current_Out, Spacing);
  848.    end New_Line;
  849.  
  850.    --------------
  851.    -- New_Page --
  852.    --------------
  853.  
  854.    procedure New_Page (File : in File_Type) is
  855.    begin
  856.       FIO.Check_Write_Status (AP (File));
  857.  
  858.       if File.Col /= 1 or else File.Line = 1 then
  859.          Putc (LM, File);
  860.       end if;
  861.  
  862.       Putc (PM, File);
  863.       File.Page := File.Page + 1;
  864.       File.Line := 1;
  865.       File.Col := 1;
  866.    end New_Page;
  867.  
  868.    procedure New_Page is
  869.    begin
  870.       New_Page (Current_Out);
  871.    end New_Page;
  872.  
  873.    -----------
  874.    -- Nextc --
  875.    -----------
  876.  
  877.    function Nextc (File : File_Type) return int is
  878.       ch : int;
  879.  
  880.    begin
  881.       ch := fgetc (File.Stream);
  882.  
  883.       if ch = EOF then
  884.          if ferror (File.Stream) /= 0 then
  885.             raise Device_Error;
  886.          end if;
  887.  
  888.       else
  889.          if ungetc (ch, File.Stream) = EOF then
  890.             raise Device_Error;
  891.          end if;
  892.       end if;
  893.  
  894.       return ch;
  895.    end Nextc;
  896.  
  897.    ----------
  898.    -- Open --
  899.    ----------
  900.  
  901.    procedure Open
  902.      (File : in out File_Type;
  903.       Mode : in File_Mode;
  904.       Name : in String;
  905.       Form : in String := "")
  906.    is
  907.       File_Control_Block : Text_AFCB;
  908.  
  909.    begin
  910.       FIO.Open (File_Ptr  => AP (File),
  911.                 Dummy_FCB => File_Control_Block,
  912.                 Mode      => To_FCB (Mode),
  913.                 Name      => Name,
  914.                 Form      => Form,
  915.                 Amethod   => 'T',
  916.                 Creat     => False,
  917.                 Text      => True);
  918.    end Open;
  919.  
  920.    ----------
  921.    -- Page --
  922.    ----------
  923.  
  924.    --  Note: we assume that it is impossible in practice for the page
  925.    --  to exceed the value of Count'Last, i.e. no check is required for
  926.    --  overflow raising layout error.
  927.  
  928.    function Page (File : in File_Type) return Positive_Count is
  929.    begin
  930.       FIO.Check_File_Open (AP (File));
  931.       return File.Page;
  932.    end Page;
  933.  
  934.    function Page return Positive_Count is
  935.    begin
  936.       return Page (Current_Out);
  937.    end Page;
  938.  
  939.    -----------------
  940.    -- Page_Length --
  941.    -----------------
  942.  
  943.    function Page_Length (File : in File_Type) return Count is
  944.    begin
  945.       FIO.Check_Write_Status (AP (File));
  946.       return File.Page_Length;
  947.    end Page_Length;
  948.  
  949.    function Page_Length return Count is
  950.    begin
  951.       return Page_Length (Current_Out);
  952.    end Page_Length;
  953.  
  954.    ---------
  955.    -- Put --
  956.    ---------
  957.  
  958.    procedure Put
  959.      (File : in File_Type;
  960.       Item : in Character)
  961.    is
  962.    begin
  963.       FIO.Check_Write_Status (AP (File));
  964.  
  965.       if File.Line_Length /= 0 and then File.Col > File.Line_Length then
  966.          New_Line (File);
  967.       end if;
  968.  
  969.       if fputc (Character'Pos (Item), File.Stream) = EOF then
  970.          raise Device_Error;
  971.       end if;
  972.  
  973.       File.Col := File.Col + 1;
  974.    end Put;
  975.  
  976.    procedure Put (Item : in Character) is
  977.    begin
  978.       FIO.Check_Write_Status (AP (Current_Out));
  979.  
  980.       if Current_Out.Line_Length /= 0
  981.         and then Current_Out.Col > Current_Out.Line_Length
  982.       then
  983.          New_Line (Current_Out);
  984.       end if;
  985.  
  986.       if fputc (Character'Pos (Item), Current_Out.Stream) = EOF then
  987.          raise Device_Error;
  988.       end if;
  989.  
  990.       Current_Out.Col := Current_Out.Col + 1;
  991.    end Put;
  992.  
  993.    ---------
  994.    -- Put --
  995.    ---------
  996.  
  997.    procedure Put
  998.      (File : in File_Type;
  999.       Item : in String)
  1000.    is
  1001.    begin
  1002.       FIO.Check_Write_Status (AP (File));
  1003.  
  1004.       if Item'Length > 0 then
  1005.  
  1006.          --  If we have bounded lines, then do things character by
  1007.          --  character (this seems a rare case anyway!)
  1008.  
  1009.          if File.Line_Length /= 0 then
  1010.             for J in Item'Range loop
  1011.                Put (File, Item (J));
  1012.             end loop;
  1013.  
  1014.          --  Otherwise we can output the entire string at once. Note that if
  1015.          --  there are LF or FF characters in the string, we do not bother to
  1016.          --  count them as line or page terminators.
  1017.  
  1018.          else
  1019.             FIO.Write_Buf (AP (File), Item'Address, Item'Length);
  1020.             File.Col := File.Col + Item'Length;
  1021.          end if;
  1022.       end if;
  1023.    end Put;
  1024.  
  1025.    procedure Put (Item : in String) is
  1026.    begin
  1027.       Put (Current_Out, Item);
  1028.    end Put;
  1029.  
  1030.    --------------
  1031.    -- Put_Line --
  1032.    --------------
  1033.  
  1034.    procedure Put_Line
  1035.      (File : in File_Type;
  1036.       Item : in String)
  1037.    is
  1038.    begin
  1039.       Put (File, Item);
  1040.       New_Line (File);
  1041.    end Put_Line;
  1042.  
  1043.    procedure Put_Line (Item : in String) is
  1044.    begin
  1045.       Put (Current_Out, Item);
  1046.       New_Line (Current_Out);
  1047.    end Put_Line;
  1048.  
  1049.    ----------
  1050.    -- Putc --
  1051.    ----------
  1052.  
  1053.    procedure Putc (ch : int; File : File_Type) is
  1054.    begin
  1055.       if fputc (ch, File.Stream) = EOF then
  1056.          raise Device_Error;
  1057.       end if;
  1058.    end Putc;
  1059.  
  1060.    ----------
  1061.    -- Read --
  1062.    ----------
  1063.  
  1064.    --  This is the primitive Stream Read routine, used when a Text_IO file
  1065.    --  is treated directly as a stream using Text_IO.Streams.Stream.
  1066.  
  1067.    procedure Read
  1068.      (File : in out Text_AFCB;
  1069.       Item : out Stream_Element_Array;
  1070.       Last : out Stream_Element_Offset)
  1071.    is
  1072.    begin
  1073.       if File.Mode /= FCB.In_File then
  1074.          raise Mode_Error;
  1075.       end if;
  1076.  
  1077.       --  Now we do the read. Since this is a text file, it is normally in
  1078.       --  text mode, but stream data must be read in binary mode, so we
  1079.       --  temporarily set binary mode for the read, resetting it after.
  1080.       --  These calls have no effect in a system (like Unix) where there is
  1081.       --  no distinction between text and binary files.
  1082.  
  1083.       set_binary_mode (fileno (File.Stream));
  1084.  
  1085.       Last :=
  1086.         Item'First +
  1087.         Stream_Element_Offset
  1088.           (fread (Item'Address, 1, Item'Length, File.Stream)) - 1;
  1089.  
  1090.       if Last < Item'Last then
  1091.          if ferror (File.Stream) /= 0 then
  1092.             raise Device_Error;
  1093.          end if;
  1094.       end if;
  1095.  
  1096.       set_text_mode (fileno (File.Stream));
  1097.    end Read;
  1098.  
  1099.    -----------
  1100.    -- Reset --
  1101.    -----------
  1102.  
  1103.    procedure Reset
  1104.      (File : in out File_Type;
  1105.       Mode : in File_Mode)
  1106.    is
  1107.    begin
  1108.       --  Don't allow change of mode for current file (RM A.10.2(5))
  1109.  
  1110.       if (File = Current_In or else
  1111.           File = Current_Out  or else
  1112.           File = Current_Error)
  1113.         and then To_FCB (Mode) /= File.Mode
  1114.       then
  1115.          raise Mode_Error;
  1116.       end if;
  1117.  
  1118.       Terminate_Line (File);
  1119.       FIO.Reset (AP (File), To_FCB (Mode));
  1120.       File.Page := 1;
  1121.       File.Line := 1;
  1122.       File.Col  := 1;
  1123.       File.Line_Length := 0;
  1124.       File.Page_Length := 0;
  1125.       File.Before_LM := False;
  1126.       File.Before_LM_PM := False;
  1127.    end Reset;
  1128.  
  1129.    procedure Reset (File : in out File_Type) is
  1130.    begin
  1131.       Terminate_Line (File);
  1132.       FIO.Reset (AP (File));
  1133.       File.Page := 1;
  1134.       File.Line := 1;
  1135.       File.Col  := 1;
  1136.       File.Line_Length := 0;
  1137.       File.Page_Length := 0;
  1138.       File.Before_LM := False;
  1139.       File.Before_LM_PM := False;
  1140.    end Reset;
  1141.  
  1142.    -------------
  1143.    -- Set_Col --
  1144.    -------------
  1145.  
  1146.    procedure Set_Col
  1147.      (File : in File_Type;
  1148.       To   : in Positive_Count)
  1149.    is
  1150.       ch : int;
  1151.  
  1152.    begin
  1153.       --  Raise Constraint_Error if out of range value. The reason for this
  1154.       --  explicit test is that we don't want junk values around, even if
  1155.       --  checks are off in the caller.
  1156.  
  1157.       if To not in Positive_Count then
  1158.          raise Constraint_Error;
  1159.       end if;
  1160.  
  1161.       FIO.Check_File_Open (AP (File));
  1162.  
  1163.       if To = File.Col then
  1164.          return;
  1165.       end if;
  1166.  
  1167.       if Mode (File) >= Out_File then
  1168.          if File.Line_Length /= 0 and then To > File.Line_Length then
  1169.             raise Layout_Error;
  1170.          end if;
  1171.  
  1172.          if To < File.Col then
  1173.             New_Line (File);
  1174.          end if;
  1175.  
  1176.          while File.Col < To loop
  1177.             Put (File, ' ');
  1178.          end loop;
  1179.  
  1180.       else
  1181.          loop
  1182.             ch := Getc (File);
  1183.  
  1184.             if ch = EOF then
  1185.                raise End_Error;
  1186.  
  1187.             elsif ch = LM then
  1188.                File.Line := File.Line + 1;
  1189.                File.Col := 1;
  1190.  
  1191.             elsif ch = PM and then File.Is_Regular_File then
  1192.                File.Page := File.Page + 1;
  1193.                File.Line := 1;
  1194.                File.Col := 1;
  1195.  
  1196.             elsif To = File.Col then
  1197.                Ungetc (ch, File);
  1198.                return;
  1199.  
  1200.             else
  1201.                File.Col := File.Col + 1;
  1202.             end if;
  1203.          end loop;
  1204.       end if;
  1205.    end Set_Col;
  1206.  
  1207.    procedure Set_Col (To : in Positive_Count) is
  1208.    begin
  1209.       Set_Col (Current_Out, To);
  1210.    end Set_Col;
  1211.  
  1212.    ---------------
  1213.    -- Set_Error --
  1214.    ---------------
  1215.  
  1216.    procedure Set_Error (File : in File_Type) is
  1217.    begin
  1218.       FIO.Check_Write_Status (AP (File));
  1219.       Current_Err := File;
  1220.    end Set_Error;
  1221.  
  1222.    ---------------
  1223.    -- Set_Input --
  1224.    ---------------
  1225.  
  1226.    procedure Set_Input (File : in File_Type) is
  1227.    begin
  1228.       FIO.Check_Read_Status (AP (File));
  1229.       Current_In := File;
  1230.    end Set_Input;
  1231.  
  1232.    --------------
  1233.    -- Set_Line --
  1234.    --------------
  1235.  
  1236.    procedure Set_Line
  1237.      (File : in File_Type;
  1238.       To   : in Positive_Count)
  1239.    is
  1240.    begin
  1241.       --  Raise Constraint_Error if out of range value. The reason for this
  1242.       --  explicit test is that we don't want junk values around, even if
  1243.       --  checks are off in the caller.
  1244.  
  1245.       if To not in Positive_Count then
  1246.          raise Constraint_Error;
  1247.       end if;
  1248.  
  1249.       FIO.Check_File_Open (AP (File));
  1250.  
  1251.       if To = File.Line then
  1252.          return;
  1253.       end if;
  1254.  
  1255.       if Mode (File) >= Out_File then
  1256.          if File.Page_Length /= 0 and then To > File.Page_Length then
  1257.             raise Layout_Error;
  1258.          end if;
  1259.  
  1260.          if To < File.Line then
  1261.             New_Page (File);
  1262.          end if;
  1263.  
  1264.          while File.Line < To loop
  1265.             New_Line (File);
  1266.          end loop;
  1267.  
  1268.       else
  1269.          while To /= File.Line loop
  1270.             Skip_Line (File);
  1271.          end loop;
  1272.       end if;
  1273.    end Set_Line;
  1274.  
  1275.    procedure Set_Line (To : in Positive_Count) is
  1276.    begin
  1277.       Set_Line (Current_Out, To);
  1278.    end Set_Line;
  1279.  
  1280.    ---------------------
  1281.    -- Set_Line_Length --
  1282.    ---------------------
  1283.  
  1284.    procedure Set_Line_Length (File : in File_Type; To : in Count) is
  1285.    begin
  1286.       --  Raise Constraint_Error if out of range value. The reason for this
  1287.       --  explicit test is that we don't want junk values around, even if
  1288.       --  checks are off in the caller.
  1289.  
  1290.       if To not in Count then
  1291.          raise Constraint_Error;
  1292.       end if;
  1293.  
  1294.       FIO.Check_Write_Status (AP (File));
  1295.       File.Line_Length := To;
  1296.    end Set_Line_Length;
  1297.  
  1298.    procedure Set_Line_Length (To : in Count) is
  1299.    begin
  1300.       Set_Line_Length (Current_Out, To);
  1301.    end Set_Line_Length;
  1302.  
  1303.    ----------------
  1304.    -- Set_Output --
  1305.    ----------------
  1306.  
  1307.    procedure Set_Output (File : in File_Type) is
  1308.    begin
  1309.       FIO.Check_Write_Status (AP (File));
  1310.       Current_Out := File;
  1311.    end Set_Output;
  1312.  
  1313.    ---------------------
  1314.    -- Set_Page_Length --
  1315.    ---------------------
  1316.  
  1317.    procedure Set_Page_Length (File : in File_Type; To : in Count) is
  1318.    begin
  1319.       --  Raise Constraint_Error if out of range value. The reason for this
  1320.       --  explicit test is that we don't want junk values around, even if
  1321.       --  checks are off in the caller.
  1322.  
  1323.       if To not in Count then
  1324.          raise Constraint_Error;
  1325.       end if;
  1326.  
  1327.       FIO.Check_Write_Status (AP (File));
  1328.       File.Page_Length := To;
  1329.    end Set_Page_Length;
  1330.  
  1331.    procedure Set_Page_Length (To : in Count) is
  1332.    begin
  1333.       Set_Page_Length (Current_Out, To);
  1334.    end Set_Page_Length;
  1335.  
  1336.    ---------------
  1337.    -- Skip_Line --
  1338.    ---------------
  1339.  
  1340.    procedure Skip_Line
  1341.      (File    : in File_Type;
  1342.       Spacing : in Positive_Count := 1)
  1343.    is
  1344.       ch : int;
  1345.  
  1346.    begin
  1347.       --  Raise Constraint_Error if out of range value. The reason for this
  1348.       --  explicit test is that we don't want junk values around, even if
  1349.       --  checks are off in the caller.
  1350.  
  1351.       if Spacing not in Positive_Count then
  1352.          raise Constraint_Error;
  1353.       end if;
  1354.  
  1355.       FIO.Check_Read_Status (AP (File));
  1356.  
  1357.       for L in 1 .. Spacing loop
  1358.          if File.Before_LM then
  1359.             File.Before_LM := False;
  1360.             File.Before_LM_PM := False;
  1361.  
  1362.          else
  1363.             ch := Getc (File);
  1364.  
  1365.             --  If at end of file now, then immediately raise End_Error. Note
  1366.             --  that we can never be positioned between a line mark and a page
  1367.             --  mark, so if we are at the end of file, we cannot logically be
  1368.             --  before the implicit page mark that is at the end of the file.
  1369.  
  1370.             --  For the same reason, we do not need an explicit check for a
  1371.             --  page mark. If there is a FF in the middle of a line, the file
  1372.             --  is not in canonical format and we do not care about the page
  1373.             --  numbers for files other than ones in canonical format.
  1374.  
  1375.             if ch = EOF then
  1376.                raise End_Error;
  1377.             end if;
  1378.  
  1379.             --  If not at end of file, then loop till we get to an LM or EOF.
  1380.             --  The latter case happens only in non-canonical files where the
  1381.             --  last line is not terminated by LM, but we don't want to blow
  1382.             --  up for such files, so we assume an implicit LM in this case.
  1383.  
  1384.             loop
  1385.                exit when ch = LM or ch = EOF;
  1386.                ch := Getc (File);
  1387.             end loop;
  1388.          end if;
  1389.  
  1390.          --  We have got past a line mark, now, for a regular file only,
  1391.          --  see if a page mark immediately follows this line mark and
  1392.          --  if so, skip past the page mark as well. We do not do this
  1393.          --  for non-regular files, since it would cause an undesirable
  1394.          --  wait for an additional character.
  1395.  
  1396.          File.Col := 1;
  1397.          File.Line := File.Line + 1;
  1398.  
  1399.          if File.Before_LM_PM then
  1400.             File.Page := File.Page + 1;
  1401.             File.Line := 1;
  1402.             File.Before_LM_PM := False;
  1403.  
  1404.          elsif File.Is_Regular_File then
  1405.             ch := Getc (File);
  1406.  
  1407.             --  Page mark can be explicit, or implied at the end of the file
  1408.  
  1409.             if (ch = PM or else ch = EOF)
  1410.               and then File.Is_Regular_File
  1411.             then
  1412.                File.Page := File.Page + 1;
  1413.                File.Line := 1;
  1414.             else
  1415.                Ungetc (ch, File);
  1416.             end if;
  1417.          end if;
  1418.  
  1419.       end loop;
  1420.    end Skip_Line;
  1421.  
  1422.    procedure Skip_Line (Spacing : in Positive_Count := 1) is
  1423.    begin
  1424.       Skip_Line (Current_In, Spacing);
  1425.    end Skip_Line;
  1426.  
  1427.    ---------------
  1428.    -- Skip_Page --
  1429.    ---------------
  1430.  
  1431.    procedure Skip_Page (File : in File_Type) is
  1432.       ch : int;
  1433.  
  1434.    begin
  1435.       FIO.Check_Read_Status (AP (File));
  1436.  
  1437.       --  If at page mark already, just skip it
  1438.  
  1439.       if File.Before_LM_PM then
  1440.          File.Before_LM := False;
  1441.          File.Before_LM_PM := False;
  1442.          File.Page := File.Page + 1;
  1443.          File.Line := 1;
  1444.          File.Col  := 1;
  1445.          return;
  1446.       end if;
  1447.  
  1448.       --  This is a bit tricky, if we are logically before an LM then
  1449.       --  it is not an error if we are at an end of file now, since we
  1450.       --  are not really at it.
  1451.  
  1452.       if File.Before_LM then
  1453.          File.Before_LM := False;
  1454.          File.Before_LM_PM := False;
  1455.          ch := Getc (File);
  1456.  
  1457.       --  Otherwise we do raise End_Error if we are at the end of file now
  1458.  
  1459.       else
  1460.          ch := Getc (File);
  1461.  
  1462.          if ch = EOF then
  1463.             raise End_Error;
  1464.          end if;
  1465.       end if;
  1466.  
  1467.       --  Now we can just rumble along to the next page mark, or to the
  1468.       --  end of file, if that comes first. The latter case happens when
  1469.       --  the page mark is implied at the end of file.
  1470.  
  1471.       loop
  1472.          exit when ch = EOF
  1473.            or else (ch = PM and then File.Is_Regular_File);
  1474.          ch := Getc (File);
  1475.       end loop;
  1476.  
  1477.       File.Page := File.Page + 1;
  1478.       File.Line := 1;
  1479.       File.Col  := 1;
  1480.    end Skip_Page;
  1481.  
  1482.    procedure Skip_Page is
  1483.    begin
  1484.       Skip_Page (Current_In);
  1485.    end Skip_Page;
  1486.  
  1487.    --------------------
  1488.    -- Standard_Error --
  1489.    --------------------
  1490.  
  1491.    function Standard_Error return File_Type is
  1492.    begin
  1493.       return Standard_Err;
  1494.    end Standard_Error;
  1495.  
  1496.    function Standard_Error return File_Access is
  1497.    begin
  1498.       return Standard_Err'Access;
  1499.    end Standard_Error;
  1500.  
  1501.    --------------------
  1502.    -- Standard_Input --
  1503.    --------------------
  1504.  
  1505.    function Standard_Input return File_Type is
  1506.    begin
  1507.       return Standard_In;
  1508.    end Standard_Input;
  1509.  
  1510.    function Standard_Input return File_Access is
  1511.    begin
  1512.       return Standard_In'Access;
  1513.    end Standard_Input;
  1514.  
  1515.    ---------------------
  1516.    -- Standard_Output --
  1517.    ---------------------
  1518.  
  1519.    function Standard_Output return File_Type is
  1520.    begin
  1521.       return Standard_Out;
  1522.    end Standard_Output;
  1523.  
  1524.    function Standard_Output return File_Access is
  1525.    begin
  1526.       return Standard_Out'Access;
  1527.    end Standard_Output;
  1528.  
  1529.    --------------------
  1530.    -- Terminate_Line --
  1531.    --------------------
  1532.  
  1533.    procedure Terminate_Line (File : File_Type) is
  1534.    begin
  1535.       FIO.Check_File_Open (AP (File));
  1536.  
  1537.       --  For file other than In_File, test for needing to terminate last line
  1538.  
  1539.       if Mode (File) /= In_File then
  1540.  
  1541.          --  If not at start of line definition need new line
  1542.  
  1543.          if File.Col /= 1 then
  1544.             New_Line (File);
  1545.  
  1546.          --  For files other than standard error and standard output, we
  1547.          --  make sure that an empty file has a single line feed, so that
  1548.          --  it is properly formatted. We avoid this for the standard files
  1549.          --  because it is too much of a nuisance to have these odd line
  1550.          --  feeds when nothing has been written to the file.
  1551.  
  1552.          elsif (File /= Standard_Err and then File /= Standard_Out)
  1553.            and then (File.Line = 1 and then File.Page = 1)
  1554.          then
  1555.             New_Line (File);
  1556.          end if;
  1557.       end if;
  1558.    end Terminate_Line;
  1559.  
  1560.    ------------
  1561.    -- Ungetc --
  1562.    ------------
  1563.  
  1564.    procedure Ungetc (ch : int; File : File_Type) is
  1565.    begin
  1566.       if ch /= EOF then
  1567.          if ungetc (ch, File.Stream) = EOF then
  1568.             raise Device_Error;
  1569.          end if;
  1570.       end if;
  1571.    end Ungetc;
  1572.  
  1573.    -----------
  1574.    -- Write --
  1575.    -----------
  1576.  
  1577.    --  This is the primitive Stream Write routine, used when a Text_IO file
  1578.    --  is treated directly as a stream using Text_IO.Streams.Stream.
  1579.  
  1580.    procedure Write
  1581.      (File : in out Text_AFCB;
  1582.       Item : in Stream_Element_Array)
  1583.    is
  1584.       Siz : constant size_t := Item'Length;
  1585.  
  1586.    begin
  1587.       if File.Mode = FCB.In_File then
  1588.          raise Mode_Error;
  1589.       end if;
  1590.  
  1591.       --  Now we do the write. Since this is a text file, it is normally in
  1592.       --  text mode, but stream data must be written in binary mode, so we
  1593.       --  temporarily set binary mode for the write, resetting it after.
  1594.       --  These calls have no effect in a system (like Unix) where there is
  1595.       --  no distinction between text and binary files.
  1596.  
  1597.       set_binary_mode (fileno (File.Stream));
  1598.  
  1599.       if fwrite (Item'Address, 1, Siz, File.Stream) /= Siz then
  1600.          raise Device_Error;
  1601.       end if;
  1602.  
  1603.       set_text_mode (fileno (File.Stream));
  1604.    end Write;
  1605.  
  1606. begin
  1607.    -------------------------------
  1608.    -- Initialize Standard Files --
  1609.    -------------------------------
  1610.  
  1611.    --  Note: the names in these files are bogus, and probably it would be
  1612.    --  better for these files to have no names, but the ACVC test insist!
  1613.    --  We use names that are bound to fail in open etc.
  1614.  
  1615.    Standard_In.Stream            := stdin;
  1616.    Standard_In.Name              := new String'("*stdin");
  1617.    Standard_In.Form              := Null_Str'Unrestricted_Access;
  1618.    Standard_In.Mode              := FCB.In_File;
  1619.    Standard_In.Is_Regular_File   := is_regular_file (fileno (stdin)) /= 0;
  1620.    Standard_In.Is_Temporary_File := False;
  1621.    Standard_In.Is_System_File    := True;
  1622.    Standard_In.Is_Text_File      := True;
  1623.    Standard_In.Access_Method     := 'T';
  1624.  
  1625.    Standard_Out.Stream            := stdout;
  1626.    Standard_Out.Name              := new String'("*stdout");
  1627.    Standard_Out.Form              := Null_Str'Unrestricted_Access;
  1628.    Standard_Out.Mode              := FCB.Out_File;
  1629.    Standard_Out.Is_Regular_File   := is_regular_file (fileno (stdout)) /= 0;
  1630.    Standard_Out.Is_Temporary_File := False;
  1631.    Standard_Out.Is_System_File    := True;
  1632.    Standard_Out.Is_Text_File      := True;
  1633.    Standard_Out.Access_Method     := 'T';
  1634.  
  1635.    Standard_Err.Stream            := stderr;
  1636.    Standard_Err.Name              := new String'("*stderr");
  1637.    Standard_Err.Form              := Null_Str'Unrestricted_Access;
  1638.    Standard_Err.Mode              := FCB.Out_File;
  1639.    Standard_Err.Is_Regular_File   := is_regular_file (fileno (stderr)) /= 0;
  1640.    Standard_Err.Is_Temporary_File := False;
  1641.    Standard_Err.Is_System_File    := True;
  1642.    Standard_Err.Is_Text_File      := True;
  1643.    Standard_Err.Access_Method     := 'T';
  1644.  
  1645.    FIO.Chain_File (AP (Standard_In));
  1646.    FIO.Chain_File (AP (Standard_Out));
  1647.    FIO.Chain_File (AP (Standard_Err));
  1648.  
  1649. end Ada.Text_IO;
  1650.